﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ATM_Software
{
    // This provides functionalities to manipulate customer and part of bussines tier
    public class CustomerManager
    {        
        CustomerDAL customerDAL;
        static private string[] loginTried = {"",""};
        public CustomerManager()
        {           
            customerDAL = new CustomerDAL();
        }
        
        // performs validation
        private bool validate(string value, string fieldName, out string message)
        {            
            switch (fieldName)
            {
                case "userid":

                    try
                    {
                        int userid = int.Parse(value);
                        if (userid < 1)
                        {
                            throw new FormatException();
                        }
                    }
                    catch (FormatException)
                    {
                        message = "\nError : Please enter Positive Integers only \nInfo : Press any key to Re-Enter";
                        return false;
                    }
                    catch (OverflowException)
                    {
                        message = "\nError : Please enter 10 digits only \nInfo : Press any key to Re-Enter";
                        return false;
                    }
                    break;

                case "accountid":

                    try
                    {
                        int accountid = int.Parse(value);
                        if (accountid < 1)
                        {
                            throw new FormatException();
                        }
                    }
                    catch (FormatException)
                    {
                        message = "\nError : Please enter Positive Integers only \nInfo : Press any key to Re-Enter";
                        return false;
                    }
                    catch (OverflowException)
                    {
                        message = "\nError : Please enter 10 digits only Info : Press any key to Re-Enter";
                        return false;
                    }
                    break;

                case "pincode":

                    try
                    {
                        if (value.Length != 5)
                        {
                            throw new Exception();
                        }
                        int pincode = int.Parse(value);
                        if (pincode < 1)
                        {
                            throw new Exception();
                        }
                    }
                    catch (Exception)
                    {
                        message = "\nError : Please enter 5 digit positive Integers only \nInfo : Press any key to Re-Enter";
                        return false;
                    }                    
                    break;

                case "balance":

                    try
                    {
                        int balance = int.Parse(value);
                        if (balance < 0)
                        {
                            throw new FormatException();
                        }
                    }
                    catch (FormatException)
                    {
                        message = "\nError : Please enter Positive Integers only \nInfo : Press any key to Re-Enter";
                        return false;
                    }
                    catch (OverflowException)
                    {
                        message = "\nError : Please enter 10 digits only \nInfo : Press any key to Re-Enter";
                        return false;
                    }
                    break;
                    
                case "login":
                                       
                    if (value == "")
                    {                        
                        message = "Error : Login is empty \nInfo : Press any key to reenter value";
                        return false;
                    }
                    if (value.All(Char.IsLetterOrDigit)==false)
                    {                        
                        message = "Error : Login contains special characters \nInfo : Press any key to reenter value";
                        return false;
                    }
                    break;

                case "name":
                    if (value == "" || value.Replace(" ", "").All(Char.IsLetter) == false)
                    {                        
                        message = "Error : Please enter alphabets only\nInfo : Press any key to reenter value";
                        return false;
                    }
                    break;

                case "type":
                    if (!(value.ToLower().Equals("savings") || value.ToLower().Equals("current")))
                    {                                               
                        message = "Error : Please enter \"savings\" or \"current\" \nInfo : Press any key to reenter value";
                        return false;
                    }
                    break;

                case "status":
                    if (!(value.ToLower().Equals("active") || value.ToLower().Equals("disable")))
                    {                                               
                        message = "Error : Please enter \"active\" or \"disable\" \nInfo : Press any key to reenter value";
                        return false;
                    }
                    break;
            }
            message = "";
            return true;
        }

        // logins a customer and at 3 wrong tries of a specific user it will disable account
        public bool Login(ref CustomerData customer)
        {
            CustomerData tempCustomer = new CustomerData(customer);
            if (customerDAL.Login(ref customer))
            {
                if (customer.Status.Equals("disable"))
                {
                    Console.WriteLine("Your account is disabled...");
                    Console.ReadKey();
                    return false;
                }
                else if (tempCustomer.PinCode == customer.PinCode)
                {
                    loginTried[0] = "";
                    loginTried[1] = "";
                    return true;
                }

                // if pin is wrong then track login
                int counter = 0;
                foreach (string tried in loginTried)
                {
                    if (tried.Equals(customer.Login))
                    {
                        counter++;
                    }
                }
                if (counter == 2) // if two tries are already and it is the third one then disable
                {
                    this.DisableAccount(ref customer);
                    Console.WriteLine("You tried 3 times with wrong pin code ...");
                    Console.WriteLine("Your account has been disabled ...");
                    Console.WriteLine("Please see the administrator ...");
                    Console.ReadKey();                    
                    loginTried[0] = "";
                    loginTried[1] = "";
                }
                else if (counter == 1)
                {
                    loginTried[1] = customer.Login;
                }
                else
                {
                    loginTried[0] = customer.Login;
                    loginTried[1] = "";
                }
                return false;                
            }
            customer.EncryptDecrypt();
            Console.WriteLine("Account with the login \"{0}\" does not exsists",customer.Login);
            Console.Write("Press any key to re login ...");
            Console.ReadKey();
            return false;
        }
        public bool DisableAccount(ref CustomerData customer)
        {
            customer.Status = "disable";
            return this.UpdateAccount(customer,false);
        }
        public void CreateAccount()
        {
            CustomerData customer = new CustomerData();
            string input = null;
            string message;
            while (true)
            {
                Console.Clear();
                Console.ResetColor();
                Console.WriteLine("\n==== Create Account ====\n");
                Console.ResetColor();
                Console.Write("Login : ");
                if (customer.Login.Equals(""))
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "login", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                       
                        continue;
                    }
                    customer.Login = input;
                    // because pinCode is by default null so it is assigned 0 for successfull encryption
                    customer.PinCode = 0;
                    customer.EncryptDecrypt();
                    
                    if (this.Search(customer,false).Count != 0)
                    {
                       Console.ResetColor();
                       Console.WriteLine("Login already exists ...");
                       Console.WriteLine("Press any key to go back ...");
                       customer.Login = "";
                       Console.ReadKey();                       
                       continue;
                    }
                    customer.EncryptDecrypt();
                    customer.PinCode = null;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.Login);
                    
                }

                Console.ResetColor();
                Console.Write("Pin Code : ");

                if (customer.PinCode == null)
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "pincode", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                      
                        customer.PinCode = null;
                        continue;
                    }
                    customer.PinCode = int.Parse(input);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.PinCode);                
                }

                Console.ResetColor();
                Console.Write("Holder Name : ");
                if (customer.Name.Equals(""))
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "name", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                        
                        continue;
                    }
                    customer.Name= input;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.Name);                    
                }

                Console.ResetColor();
                Console.Write("Type (savings,current) : ");
                if (customer.Type == "")
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "type", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                        
                        continue;
                    }
                    customer.Type = input;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.Type);                    
                }
                
                
                Console.ResetColor();
                Console.Write("Starting Balance : ");
                if (customer.Balance == null)
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "balance", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                       
                        continue;
                    }
                    customer.Balance = int.Parse(input);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.Balance);                    
                }

                Console.ResetColor();
                Console.Write("Status : ");
                if (customer.Status == "")
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    input = Console.ReadLine();
                    if (validate(input, "status", out message) == false)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(message);
                        Console.ReadKey();                        
                        continue;
                    }
                    customer.Status = input;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(customer.Status);                    
                }
                break;                
            }
            customer.EncryptDecrypt();
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("\nAccount Successfully  Created  –  the  account  number  assigned is : "
                + customerDAL.CreateAccount(customer) + "\n");
            Console.ResetColor();
            Console.Write("Press any key key to go back");
            Console.ReadKey();
        }
        public bool DeleteAccount()
        {
            Console.Clear();
            Console.WriteLine("\n==== Delete Account ====\n");                        
            Console.Write("Enter the account number to which you want to delete : ");
            String message;
            Console.ForegroundColor = ConsoleColor.Green;
            string accountNo = Console.ReadLine();
            Console.ResetColor();
            bool flag = false;
            while (validate(accountNo, "accountid", out message) == false)
            {                
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(message);
                Console.ReadKey();
                Console.ResetColor();
                Console.Clear();         
                Console.Write("Enter the account number to which you want to delete : ");
                Console.ForegroundColor = ConsoleColor.Green;
                accountNo = Console.ReadLine();
                flag = true;                
            }
           
            CustomerData toBeDeleted = new CustomerData();
            toBeDeleted.AccountId = int.Parse(accountNo);
            List<CustomerData> customersList = Search(toBeDeleted,false);
            if (flag)
            {
                Console.Write("Enter the account number to which you want to delete : " + accountNo);
            }
            
            if (customersList.Count != 0)
            {
                toBeDeleted = customersList[0];                
                Console.ResetColor();
                Console.Write("You wish to delete the account held by {0}; if this  information  is  correct  please  re-enter  the  account number:",
                    toBeDeleted.Name);
                string confirmAccount = Console.ReadLine();
                while (validate(confirmAccount, "accountid", out message) == false)
                {                
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write(message);
                    Console.ResetColor();
                    Console.ReadKey();
                    Console.Clear();
                    Console.WriteLine("Enter the account number to which you want to delete : " + accountNo);                    
                    Console.Write("You wish to delete the account held by {0}; if this  information  is  correct  please  re-enter  the  account number:",
                    toBeDeleted.Name);
                    Console.ForegroundColor = ConsoleColor.Green;
                    confirmAccount = Console.ReadLine();
                    Console.ResetColor();
                }
                int account = int.Parse(accountNo);
                if (account == int.Parse(accountNo))// account and re enter account is equals
                {
                    if (customerDAL.DeleteAccount(toBeDeleted))
                    {
                        Console.Clear();                        
                        Console.ResetColor();
                        Console.WriteLine("Account Deleted Successfully");
                        Console.WriteLine("Press any key to go back");
                        Console.ReadKey();
                    }
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Error : The re-typed account number is invalid");
                    Console.WriteLine("Press any key to go back");
                    Console.ResetColor();
                    Console.ReadKey();
                    return false;
                }
                
            return true;
            }            
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("This account number does not exsists");
                Console.WriteLine("Press any key to go back");
                Console.ResetColor();
                Console.ReadKey();
                return false;
            }
        }

        // this search function can take an object to be searched
        // or it can be called to take input criteria then it will create object and search
        // second argument AdminSearch specifies wheter to take input criteria or not
        // by default it will take input criteria
        public List<CustomerData> Search(CustomerData customer = null, bool AdminSearch = true)
        {

            if (!AdminSearch && customer != null)
            {
                return customerDAL.Search(customer);
            }
            else
            {
                Console.Clear();
                Console.WriteLine("\n==== Search ====\n");
                customer = new CustomerData();
                Console.Write("Account ID : ");
                Console.ForegroundColor = ConsoleColor.Green;
                string accountId = Console.ReadLine();
                // if account no is not empty then ensure accountno is valid integer value
                // otherwise send it empty
                string message;
                if (!accountId.Equals(""))
                {
                    if (validate(accountId, "accountid", out message) == false)
                    {
                        customer.AccountId = 0;
                    }
                    else
                    {
                        customer.AccountId = int.Parse(accountId);
                    }
                }

                Console.ResetColor();
                Console.Write("\nUser ID : ");
                Console.ForegroundColor = ConsoleColor.Green;
                string userId = Console.ReadLine();
                // if userid is not empty then ensure accountno is valid integer value
                // otherwise send it empty              
                if (!userId.Equals(""))
                {
                    if (validate(accountId, "userid", out message) == false)
                    {
                        customer.UserId = 0;
                    }
                    else
                    {
                        customer.UserId = int.Parse(accountId);
                    }
                }

                Console.ResetColor();
                Console.Write("\nHolder Name : ");
                Console.ForegroundColor = ConsoleColor.Green;
                customer.Name = Console.ReadLine();

                Console.ResetColor();
                Console.Write("\nType (Savings, Current) : ");
                Console.ForegroundColor = ConsoleColor.Green;
                customer.Type = Console.ReadLine();

                Console.ResetColor();
                Console.Write("\nBalance : ");
                Console.ForegroundColor = ConsoleColor.Green;
                string balance = Console.ReadLine();
                // if balance is not empty then ensure accountno is valid integer value
                // otherwise send it empty              
                if (!balance.Equals(""))
                {
                    if (validate(balance, "balance", out message) == false)
                    {
                        customer.Balance = null;
                    }
                    else
                    {
                        customer.Balance = int.Parse(balance);
                    }
                }

                Console.ResetColor();
                Console.Write("\nStatus : ");
                Console.ForegroundColor = ConsoleColor.Green;
                customer.Status = Console.ReadLine();
                Console.ResetColor();

                List<CustomerData> customerList = customerDAL.Search(customer);

                Console.WriteLine("\n==== SEARCH RESULTS ====");
                Console.WriteLine("\nRecords Found : {0}\n",customerList.Count);
                Console.WriteLine("AccountID   UserID\tHolder\t   Type\t    Balance\tStatus\n");                
                if (customerList.Count != 0)
                {
                    foreach (CustomerData cust in customerList)
                    {
                        Console.WriteLine("{0}\t{1,8}\t{2}\t{3,10}\t{4}\t{5}",
                            cust.AccountId,cust.UserId,cust.Name,cust.Type,cust.Balance,cust.Status);
                    }
                    Console.WriteLine();
                    Console.WriteLine("Press any key to go back");
                    Console.ReadKey();
                    return customerList;
                }
                Console.WriteLine("Press any key to go back");
                Console.ReadKey();
                return null;                
            }
        }
        public bool UpdateAccount ( CustomerData customer = null, bool AdminSearch = true)
        {

            if (!AdminSearch && customer != null)
            {                
                return customerDAL.UpdateAccount(customer);
            }
            else if (AdminSearch && customer == null)
            {
                Console.Clear();
                Console.WriteLine("\n==== Update Account ====\n");                
                Console.Write("Enter the account number : ");
                String message;
                Console.ForegroundColor = ConsoleColor.Green;
                string accountNo = Console.ReadLine();
                Console.ResetColor();
                bool flag = false;
                while (validate(accountNo, "accountid", out message) == false)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write(message);
                    Console.ResetColor();
                    Console.ReadKey();
                    Console.Clear();
                    Console.Write("Enter the account number : ");
                    Console.ForegroundColor = ConsoleColor.Green;
                    accountNo = Console.ReadLine();
                    flag = true;
                }
                if (flag)
                {
                    Console.Write("Enter the account number : " + accountNo);
                }

                customer = new CustomerData();
                customer.AccountId = int.Parse(accountNo);
                List<CustomerData> customersList = Search(customer, false);

                if (customersList.Count != 0)
                {

                    customer = customersList[0];
                    flag = false;
                    while (!flag)
                    {
                        Console.Clear();
                        Console.ResetColor();
                        Console.WriteLine(customer);
                        Console.ResetColor();
                        Console.Write("\nLogin : ");
                        Console.ForegroundColor = ConsoleColor.Green;
                        string temp = Console.ReadLine();
                        if (!temp.Equals(""))
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                            if (validate(temp, "login", out message) == false)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.Write(message);
                                Console.ReadKey();
                                continue;
                            }
                            customer.Login = temp;
                        }

                        Console.ResetColor();
                        Console.Write("\nPin Code : ");
                        Console.ForegroundColor = ConsoleColor.Green;
                        temp = Console.ReadLine();
                        if (!temp.Equals(""))
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                            if (validate(temp, "pincode", out message) == false)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.Write(message);
                                Console.ReadKey();
                                continue;
                            }
                            customer.PinCode = int.Parse(temp);
                        }

                        Console.ResetColor();
                        Console.Write("\nHolder Name : ");
                        Console.ForegroundColor = ConsoleColor.Green;
                        temp = Console.ReadLine();
                        if (!temp.Equals(""))
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                            if (validate(temp, "name", out message) == false)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.Write(message);
                                Console.ReadKey();
                                continue;
                            }
                            customer.Name = temp;
                        }

                        Console.ResetColor();
                        Console.Write("\nStatus : ");
                        Console.ForegroundColor = ConsoleColor.Green;
                        temp = Console.ReadLine();
                        if (!temp.Equals(""))
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                            if (validate(temp, "status", out message) == false)
                            {
                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.Write(message);
                                Console.ReadKey();
                                continue;
                            }
                            customer.Status = temp;
                        }
                        flag = true;
                    }
                    Console.ResetColor();
                    customerDAL.UpdateAccount(customer);
                    Console.WriteLine("Account has been successfully updated");
                    Console.WriteLine("Press any key to go back");
                    Console.ReadKey();
                    return true;
                }
                return false;
            }
            return false;
        }

        public void DisplayBalance(CustomerData customer)
        {
            Console.Clear();
            Console.WriteLine("\n==== Balace Information ====\n");
            Console.WriteLine("Account number : " + customer.AccountId);
            Console.WriteLine("Date : " + DateTime.Now.ToString("dd/MM/yyyy"));            
            Console.WriteLine("Balance : " + customer.Balance);
            Console.Write("Press any key to go back ...");
            Console.ReadKey();
        }

        public void ViewReports()
        {
            string choice = "";
            Console.Clear();
            Console.WriteLine("\n==== View Reports ====\n");
            Console.WriteLine("1---Accounts By Amount");
            Console.WriteLine("2---Accounts By Date");
            Console.Write("\nPlease select one of the above options : ");
            Console.ForegroundColor = ConsoleColor.Green;
            choice = Console.ReadLine();
            Console.ResetColor();
            if (choice.Equals("1"))
            {
                int minAmount = 0;
                int maxAmount = 0;

                try
                {
                
                    Console.Write("Enter the minimum amount : ");
                    Console.ForegroundColor = ConsoleColor.Green;
                    minAmount = int.Parse(Console.ReadLine());
                    Console.ResetColor();
                    if (minAmount <= 0)
                    {
                        throw new Exception();
                    }

                    Console.Write("Enter the maximum amount : ");
                    Console.ForegroundColor = ConsoleColor.Green;
                    maxAmount = int.Parse(Console.ReadLine());
                    Console.ResetColor();
                    if (maxAmount <= 0)
                    {
                        throw new Exception();
                    }
                    List<CustomerData> customersList = customerDAL.GetAllAcounts();
                    if (customersList.Count != 0)
                    {                        
                        Console.WriteLine("\n==== SEARCH RESULTS ====");                        
                        Console.WriteLine("AccountID   UserID\tHolder\t   Type\t    Balance\tStatus\n");
                        foreach (CustomerData cust in customersList)
                        {
                            if (cust.Balance >= minAmount && cust.Balance <= maxAmount)
                            {
                                Console.WriteLine("{0}\t{1,8}\t{2}\t{3,10}\t{4}\t{5}",
                                cust.AccountId, cust.UserId, cust.Name, cust.Type, cust.Balance, cust.Status);    
                            }                            
                        }
                        Console.WriteLine();
                        Console.WriteLine("Press any key to go back");
                        Console.ReadKey();                        
                    }                    
                }
                catch (Exception)
                {
                    Console.WriteLine("Enter possitve integer valued ammount not more than 10 digits long ...");
                    Console.WriteLine("Press any key to go back ...");
                    Console.ReadKey();
                }
            }
            else if (choice.Equals("2"))
            {
                try
                {

                    string startDate = null;
                    string endDate = null;
                    Console.Write("Enter the starting date : ");
                    Console.ForegroundColor = ConsoleColor.Green;
                    startDate = Console.ReadLine();
                    Console.ResetColor();
                    Console.Write("Enter the ending date : ");
                    Console.ForegroundColor = ConsoleColor.Green;
                    endDate = Console.ReadLine();
                    Console.ResetColor();
                    string[] tok = startDate.Split('/');
                    string[] tok1 = endDate.Split('/');
                    //converting strating and ending dates in datetime object to compare
                    DateTime start = new DateTime(int.Parse(tok[2]), int.Parse(tok[1]), int.Parse(tok[0]));
                    DateTime end = new DateTime(int.Parse(tok1[2]), int.Parse(tok1[1]), int.Parse(tok1[0]));                    
                    List<TransactionData> transactions = new TransactionDAL().GetAllTransactions();
                    if (transactions.Count != 0)
                    {
                        Console.WriteLine("\n==== SEARCH RESULTS ====");
                        Console.WriteLine("Type   \t\tAccountID\t    Amount\tDate\n");
                        foreach (TransactionData record in transactions)
                        {
                            string[] tokens = record.Date.Split('/');
                            DateTime transDate = new DateTime(int.Parse(tokens[2]), int.Parse(tokens[1]), int.Parse(tokens[0]));                    
                            if (DateTime.Compare(transDate, start) >= 0 && DateTime.Compare(transDate, end) <= 0)
                            {
                                Console.WriteLine("{0}\t{1,8}\t{2,8}\t{3,10}",
                                record.TransactionType, record.AccountId, record.Ammount, record.Date);
                            }
                        }
                        Console.WriteLine();
                        Console.WriteLine("Press any key to go back");
                        Console.ReadKey();
                    }
                }
                catch (Exception)
                {
                    Console.WriteLine("Please enter date in dd/mm/yyyy format ...");
                    Console.WriteLine("Press any key to go back ...");
                    Console.ReadKey();
                }
                
            }
        }
    }
}

